//! Setup compilation for an external piece of client code
#define GAMEENGINE_DLL_IMPORT

#include <GameEngine/Multimedia/music.h>
#include <GameEngine/Multimedia/music_observer.h>

#include <GameEngine/Graphics/Meshes/trgl_mesh.h>
#include <GameEngine/Graphics/Meshes/trgl_mesh_creator.h>
#include <GameEngine/Graphics/Meshes/mesh_renderer.h>
#include <GameEngine/Graphics/Lighting/scene_light.h>
#include <GameEngine/Graphics/Widget/gl_widget.h>
#include <GameEngine/Graphics/Shaders/shader_program.h>
#include <GameEngine/GameEngine/square_map_renderer.h>
#include <GameEngine/GameEngine/hex_map_renderer.h>

#include <GameEngine/Maps/square_map.h>
#include <GameEngine/Maps/map_cell.h>
#include <GameEngine/AI/PathFinding/astar.h>

#include <GameEngine/Core/timer.h>
#include <GameEngine/Core/Memory/memory_manager.h>
#include <GameEngine/Geometry/type_defs.h>

#include <GameEngine/UnitTest/unit_test.h>

#include <niflib/niflib.h>
#include <niflib/obj/NiObject.h>
#pragma warning( push )
#pragma warning( disable : 4996 )
#include <niflib/obj/NiNode.h>
#pragma warning( pop )
#include <niflib/obj/NiTriStrips.h>
#include <niflib/obj/NiTexturingProperty.h>
#include <niflib/obj/NiSourceTexture.h>
#include <niflib/obj/BSXFlags.h>

#include <iostream>

#include <QtGui/QApplication>

using namespace GameEngine;




#ifndef DOXYGEN_IGNORE
#define MAP_WIDTH 32
#define MAP_HEIGHT 16
void nif_transform(Niflib::NiNodeRef& node);
#endif




//! Main function of the GameEngine test program
/*!
 @param argc The number of arguments of the program (ignored)
 @param argv The arguments of the program (ignored)
 @return The exit code
 */
int main(int argc, char** argv) {
	QApplication app(argc, argv);

/*
	// Create a hexagonal map
	HexMap hxmap(16*MAP_WIDTH,16*MAP_HEIGHT);

	// Create a square map
	SquareMap sqmap(MAP_WIDTH,MAP_HEIGHT);

	// Build terrain description
	// Two terrains: grass is walkable, wall is inaccessible
	{{
		TerrainDescriptor grass_desc;
		grass_desc.add_displacement_type(Displacement::Walkable);
		grass_desc.set_speed(Displacement::Walkable);
		sqmap.terrains().add_terrain(TerrainDescriptor::Grass, grass_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Grass, grass_desc);
		TerrainDescriptor wall_desc;
		wall_desc.add_displacement_type(Displacement::Inaccessible);
		wall_desc.set_speed(Displacement::Inaccessible, 0);
		sqmap.terrains().add_terrain(TerrainDescriptor::Wall, wall_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Wall, wall_desc);
	}}

	{{
		for ( Map::MapIndex x = 0; x < hxmap.width(); ++x ) {
			for ( Map::MapIndex y = 0; y < hxmap.height(); ++y ) {
				hxmap.get_cell(x,y)->terrain() = TerrainDescriptor::Grass;
			}
		}
	}}

	// Search shortest path for a unit that can walk
	std::list<HexMapSearch::Node> hxlist;
	{{
		HexMapSearch::Node entry = hxmap.get_array_index(0,0);
		HexMapSearch::Node exit = hxmap.get_array_index(16*MAP_WIDTH-1,16*MAP_HEIGHT-1);

		Displacement::DisplacementTypes displacements = Displacement::Walkable;
		HexMapSearch search(hxmap, displacements);

		HexMapSearchHeuristic heuristic(hxmap);
		Timer time;
		int nb = 1;
		for ( int k = 0; k < nb; ++k ) {
			hxlist.clear();
			AStar<HexMapSearch, HexMapSearchHeuristic>::find_path(hxlist, search, entry, exit, heuristic);
		}
		std::cout << "Elapsed time = " << ( time.elapsed_time() / (double)nb ) << std::endl;
	}}

	{{
		Music zique("..\\GameEngineMisc\\data\\Vampire.mp3");
		zique.play();
		zique.set_volume(10);
	}}
*/

	/*
	// Build map
	{{
		int map_desc[MAP_HEIGHT][MAP_WIDTH] = {
			// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
			  { 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, //0
			  { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, //1
			  { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, //2
			  { 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, //3
			  { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 }, //4
			  { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, //5
			  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, //6
			  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 3, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, //7
			  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, //8
			  { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, //9
			  { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0 }, //10
			  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, //11
			  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 }, //12
			  { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, //13
			  { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, //14
			  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, //15
		};
		for ( int x = 0; x < MAP_WIDTH; ++x ) {
			for ( int y = 0; y < MAP_HEIGHT; ++y ) {
				if ( map_desc[y][x] == 0 ) {
					sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Grass;
					hxmap.get_cell(x,y)->terrain() = TerrainDescriptor::Grass;
				}
				else {
					sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Wall;
					hxmap.get_cell(x,y)->terrain() = TerrainDescriptor::Wall;
				}
			}
		}
	}}
	*/

	/*
	// Build terrain description
	{{
		// Sea
		TerrainDescriptor sea_desc;
		sea_desc.add_displacement_type(Displacement::Walkable);
		sea_desc.set_speed(Displacement::Walkable, 0.8f);
		sqmap.terrains().add_terrain(TerrainDescriptor::Sea, sea_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Sea, sea_desc);

		// Sand
		TerrainDescriptor sand_desc;
		sand_desc.add_displacement_type(Displacement::Walkable);
		sand_desc.set_speed(Displacement::Walkable, 0.01f);
		sqmap.terrains().add_terrain(TerrainDescriptor::Sand, sand_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Sand, sand_desc);

		// Grass
		TerrainDescriptor grass_desc;
		grass_desc.add_displacement_type(Displacement::Walkable);
		grass_desc.set_speed(Displacement::Walkable, 0.9f);
		sqmap.terrains().add_terrain(TerrainDescriptor::Grass, grass_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Grass, grass_desc);

		// Sea
		TerrainDescriptor swamp_desc;
		swamp_desc.add_displacement_type(Displacement::Walkable);
		swamp_desc.set_speed(Displacement::Walkable, 0.3f);
		sqmap.terrains().add_terrain(TerrainDescriptor::Swamp, swamp_desc);
		hxmap.terrains().add_terrain(TerrainDescriptor::Swamp, swamp_desc);
	}}

	// Build map
	{{
		int map_desc[MAP_HEIGHT][MAP_WIDTH] = {
			// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 0
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 1
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 }, // 2
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 3
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 4
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 5
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3 }, // 6
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3 }, // 7
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 8
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3 }, // 9
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 }, // 10
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, // 11
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, // 12
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, // 13
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 }, // 14
			 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 }  // 15
		};
		for ( int x = 0; x < MAP_WIDTH; ++x ) {
			for ( int y = 0; y < MAP_HEIGHT; ++y ) {
				if ( map_desc[y][x] == 0 ) sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Sea;
				else if ( map_desc[y][x] == 1 ) sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Sand;
				else if ( map_desc[y][x] == 2 ) sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Grass;
				else sqmap.get_cell(x,y)->terrain() = TerrainDescriptor::Swamp;
			}
		}
	}}
	*/

/*
	// Search shortest path for a unit that can walk
	std::list<SquareMapSearch::Node> list;
	{{
		SquareMapSearch::Node entry = sqmap.get_array_index(0,0);
		// SquareMapSearch::Node exit = sqmap.get_array_index(0,9);
		SquareMapSearch::Node exit = sqmap.get_array_index(31,15);

		Displacement::DisplacementTypes displacements = Displacement::Walkable;
		SquareMapSearch search(sqmap, displacements);

		SquareMapSearchHeuristic heuristic(sqmap);
		AStar<SquareMapSearch, SquareMapSearchHeuristic>::find_path(list, search, entry, exit, heuristic);
	}}
*/

//*
	{{
		// Read the objects from the NIF file
		GEString nifname = "../GameEngineMisc/data/meshes/corvette01.nif";
		GEString nifname2 = "../GameEngineMisc/data/meshes/corvette02.nif";
		Niflib::NifInfo info;
		Niflib::NiObjectRef root = Niflib::ReadNifTree(nifname, &info);
		Niflib::NiNodeRef node = Niflib::DynamicCast<Niflib::NiNode>( root );

		nif_transform( node );

		// Save NIF file
		Niflib::WriteNifTree(nifname2, root, info);
	}}

//	*/

	// Create an OpenGL widget
	GLWidget* widget = MemoryManager::instance()->allocate<GLWidget>();
	widget->manipulator()->camera().target() = Point3d<float>(0.0f,0.0f,0.0f);
	widget->manipulator()->camera().eye() = Point3d<float>(
		4.0f*sqrt(2.0f) + widget->manipulator()->camera().target().x(),
		4.0f*sqrt(2.0f) + widget->manipulator()->camera().target().y(),
		8.0f            + widget->manipulator()->camera().target().z()
	);
	widget->manipulator()->camera().zoom() = -1.0f;
	widget->manipulator()->update();
	widget->show();

	// Create a square map
//	sqmap.map_box().v1() = Vector2d<float>(2,0);
//	SquareMapRenderer* sqmap_renderer = MemoryManager::instance()->allocate<SquareMapRenderer>();
//	sqmap_renderer->build(sqmap, &list);
//	widget->scene().add_element( sqmap_renderer );

	// Create a hexagonal map
//	hxmap.map_box().v1() = Vector2d<float>(2,0);
//	HexMapRenderer* hxmap_renderer = MemoryManager::instance()->allocate<HexMapRenderer>();
//	hxmap_renderer->build(hxmap, &hxlist);
//	widget->scene().add_element( hxmap_renderer );

	// Create a light
	SceneLight* light = MemoryManager::instance()->allocate<SceneLight>();
	light->position() = widget->manipulator()->camera().eye();
	light->light_index() = 0;
	widget->scene().add_element( light );

	// Create another light
	SceneLight* light2 = MemoryManager::instance()->allocate<SceneLight>();
	light2->position() = Point3d<float>(
		-widget->manipulator()->camera().eye().x(),
		-widget->manipulator()->camera().eye().y(),
		widget->manipulator()->camera().eye().z()
	);
	light2->light_index() = 1;
	widget->scene().add_element( light2 );

	{{
//		TrglMesh test; test.load_obj_file("../GameEngineMisc/data/meshes/Corvette_sail.obj");
//		TrglMesh test2; test2.load_obj_file("../GameEngineMisc/data/meshes/Drakkar_sail_tent.obj");
//		test.merge(test2);
//		test.save_bin_file("../GameEngineMisc/data/meshes/Test.bin");
	}}

	TrglMesh* mesh = MemoryManager::instance()->allocate<TrglMesh>();

//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Fisher_boat_sail.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Fisher_boat_idle.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Corvette_idle.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Corvette_sail.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Drakkar_sail.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Drakkar_sail_tent.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Drakkar_idle_tent.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/Drakkar_sail_tent2.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/CogSail.obj", 0.0007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Bateaux/CogIdle.obj", 0.0003f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Fisher_boat_sail.obj");
//	mesh->save_bin_file("../GameEngineMisc/data/meshes/Test.bin");
//	mesh->load_bin_file("../GameEngineMisc/data/meshes/Test.bin", 0.0007f);

//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Vegetation/Saule.obj", 0.7f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Vegetation/Bush.obj", 0.7f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Vegetation/QuakingAspen.obj", 0.7f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/Vegetation/QuakingAspen.obj", 0.7f);

//	mesh->load_bin_file("../GameEngineMisc/data/meshes/Fisher_boat_sail.bin", 0.0007f);
	
//	mesh->load_nif_file("../GameEngineMisc/data/meshes/corvette02.nif", 0.0007f);
//	mesh->load_3ds_file("../GameEngineMisc/data/meshes/weeping_willow.3DS");
//	mesh->save_3ds_file("../GameEngineMisc/data/meshes/test.3DS");
//	std::cout << "|\n|\n|\n|\n|" << std::endl;
	mesh->load_obj_file("../GameEngineMisc/data/meshes/chest_002.obj", 0.007f);
//	mesh->load_obj_file("../GameEngineMisc/data/meshes/weeping_willow.obj", 0.07f);

	MeshRenderer* renderer = MemoryManager::instance()->allocate<MeshRenderer>();
	renderer->set_mesh(mesh);
	renderer->transformer().rotate(Angle<float>(90.0f,Angles::Deg), Vector3d<float>(1,0,0));
	renderer->transformer().rotate(Angle<float>(180.0f,Angles::Deg), Vector3d<float>(0,0,1));

//	MeshRenderer* renderer2 = MemoryManager::instance()->allocate<MeshRenderer>(*renderer);
//	MeshRenderer* renderer3 = MemoryManager::instance()->allocate<MeshRenderer>(*renderer);

	widget->scene().add_element(renderer);

//	renderer2->transformer().translate(Vector3d<float>(1,0,0));
//	widget->scene().add_element(renderer2);

//	renderer3->transformer().translate(Vector3d<float>(0,1,0));
//	widget->scene().add_element(renderer3);


	// Create a movie
//	Phonon::VideoPlayer *player = new Phonon::VideoPlayer(Phonon::VideoCategory);
//	player->show();
//	QObject::connect(player, SIGNAL(finished()), player, SLOT(deleteLater()));
//	player->play(Phonon::MediaSource("data/Cloudspin.avi"));

	// Run unit tests
	bool test = UnitTest::test();
//	std::cout << "Nb bytes used = " << MemoryManager::instance()->bytes() << std::endl;

	return app.exec();
}



#ifndef DOXYGEN_IGNORE

//! Sandbox function used to transform nif files so that they can be rendered correctly with GameEngine
/*!
 *  For instance, GameEngine is not able to read dds files, which must be converted to another format.
 */
void nif_transform(Niflib::NiNodeRef& node) {
	// Iterate over the children of the root node
	std::vector< Niflib::NiAVObjectRef > objs = node->GetChildren();
	for ( std::vector< Niflib::NiAVObjectRef >::const_iterator it = objs.begin(); it != objs.end(); ++it ) {
		// Find node data
		if ( (*it)->IsDerivedType(Niflib::NiNode::TYPE) == true ) {
			Niflib::NiNodeRef n = Niflib::DynamicCast<Niflib::NiNode>( *it );
			nif_transform( n );
		}

		// Find triangle strip data
		if ( (*it)->IsDerivedType(Niflib::NiTriStrips::TYPE) == false ) continue;
		Niflib::NiTriStripsRef strips = Niflib::DynamicCast<Niflib::NiTriStrips>( *it );

		// Get material properties
		std::vector<Niflib::NiPropertyRef> properties = strips->GetProperties();
		for ( std::vector<Niflib::NiPropertyRef>::const_iterator pit = properties.begin(); pit != properties.end(); ++pit ) {
			// Texturing properties
			if ( (*pit)->IsDerivedType(Niflib::NiTexturingProperty::TYPE) == false ) continue;

			// Cast the texturing property
			Niflib::NiTexturingPropertyRef prop = Niflib::DynamicCast<Niflib::NiTexturingProperty>( *pit );

			// Get the texture file
			for ( int k = 0; k < prop->GetTextureCount(); ++k ) {
				Niflib::TexDesc desc = prop->GetTexture(k);
				if ( desc.source == nil ) continue;
				GEString filename = desc.source->GetTextureFileName();

				// Change file name
				QString str = filename.c_str();
				QStringList list = str.split("\\");
				if ( list.isEmpty() == false ) {
					QStringList::iterator lit = list.end();
					--lit;
					QString fname = *lit;
					fname.replace(".dds",".png");
					fname.replace(" ","_");
					GEString nname = "..\\textures\\";
					nname += fname.toAscii().constData();
					desc.source->SetExternalTexture( nname );
					prop->SetTexture(k,desc);
				}
			}
		}
	}
}

#endif
